﻿using Abp.Dependency;
using Castle.Core.Logging;
using GN.Pay.Core.Entities;
using GN.Pay.Core.Exceptions;
using GN.Pay.Core.Tasks;
using GN.Pay.Core.Tasks.Queue;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static GN.Pay.Core.Consts;
using static GN.Pay.Core.Consts.TaskConstant;

namespace GN.Pay.Core.Tasks.Impl
{
    /// <summary>
    /// 任务队列工作池
    /// 此类必须以单实例方式注入
    /// </summary>
    public class TaskQueueWorkPool : Abp.AbpServiceBase, ITaskQueueWorkPool, IDisposable
    {
        private System.Timers.Timer time;

        private static object QueueTotalLock = new object();

        /// <summary>
        /// 
        /// </summary>
        private int QueueTotalSeconds = 0;

        /// <summary>
        /// 队列错误任务锁
        /// </summary>
        private static object QueueErrorTotalLock = new object();

        /// <summary>
        /// 队列错误任务计数
        /// </summary>
        private int QueueErrorTotalSeconds = 0;

        private readonly IIocManager iocManager;
        private readonly ConsumerQueueStartManager consumerQueueStartManager;
        private readonly IQueueManager queueManager;

        /// <summary>
        /// 实例化 TaskQueueWorkPool 类新实例
        /// </summary>
        /// <param name="iocManager"></param>
        /// <param name="queueManager"></param>
        /// <param name="consumerQueueStartManager"></param>
        public TaskQueueWorkPool(IIocManager iocManager,
            IQueueManager queueManager,
            ConsumerQueueStartManager consumerQueueStartManager)
        {
            this.iocManager = iocManager;
            this.queueManager = queueManager;
            this.IsStart = false;
            this.consumerQueueStartManager = consumerQueueStartManager;
            this.consumerQueueStartManager.Add(iocManager.Resolve<IChannelPayNotifyConsumerQueue>());
            this.consumerQueueStartManager.Add(iocManager.Resolve<IChannelRefundNotifyConsumerQueue>());
            this.consumerQueueStartManager.Add(iocManager.Resolve<IChannelTransfersNotifyConsumerQueue>());
            this.consumerQueueStartManager.Add(iocManager.Resolve<IClientHttpNotifyConsumerQueue>());
            this.consumerQueueStartManager.Add(iocManager.Resolve<IClientRefundConsumerQueue>());
            this.consumerQueueStartManager.Add(iocManager.Resolve<IClientTransfersConsumerQueue>());
            this.consumerQueueStartManager.Add(iocManager.Resolve<IConsumerResetQueue>());
            this.consumerQueueStartManager.Add(iocManager.Resolve<IPayApplyExpireConsumerQueue>());
        }

        /// <summary>
        /// 获取是否启动
        /// </summary>
        public bool IsStart { get; private set; }

        /// <summary>
        /// 启动
        /// </summary>
        public bool Start()
        {
            lock (this)
            {
                if (this.IsStart)
                {
                    return false;
                }
                if (this.time != null)
                {
                    this.time.Elapsed -= Time_Elapsed;
                    this.time.Stop();
                }

                this.time = new System.Timers.Timer(1000);
                this.time.Elapsed += Time_Elapsed;
                this.QueueTotalSeconds = 0;
                this.time.Start();
                this.IsStart = true;
                return true;
            }
        }

        /// <summary>
        /// 停止
        /// </summary>
        public bool Stop()
        {
            lock (this)
            {
                if (!this.IsStart)
                {
                    return false;
                }
                if (this.time != null)
                {
                    this.time.Elapsed -= Time_Elapsed;
                    this.time.Stop();
                    this.time.Dispose();
                    this.time = null;
                }
                this.QueueTotalSeconds = 0;
                this.IsStart = false;
                return true;
            }
        }

        private void Time_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            IncrementQueueTotalSeconds();
            IncrementQueueErrorTotalSeconds();
        }

        /// <summary>
        /// 启动消费
        /// </summary>
        private void IncrementQueueTotalSeconds()
        {
            lock (QueueTotalLock)
            {
                QueueTotalSeconds++;
                if (QueueTotalSeconds >= 10)
                {
                    QueueTotalSeconds = 0;
                    if (!consumerQueueStartManager.IsComplete)
                    {
                        consumerQueueStartManager.StartOrCheck();
                    }                    
                }
            }
        }

        /// <summary>
        /// 队列重置
        /// </summary>
        private void IncrementQueueErrorTotalSeconds()
        {
            lock (QueueErrorTotalLock)
            {
                QueueErrorTotalSeconds++;
                if (QueueErrorTotalSeconds >= 600)
                {
                    QueueErrorTotalSeconds = 0;
                    QueueReset();
                }
            }
        }

        /// <summary>
        /// 重入队列
        /// </summary>
        /// <param name="resetType">重置类型</param>
        /// <returns></returns>
        private Task QueueReset()
        {
            return Task.Run(() =>
            {
                long value = TaskMonitor.Read(TaskMonitorType.NotifyErrorQueueType, true);
                if (value > 0)
                {
                    try
                    {
                        var msg = new QueueResetMessage() { ResetCount = value };
                        queueManager.Publish(QueueType.QueueReset, new RabbitMQ.GNClient.ObjectMessage(msg), null);
                    }
                    catch (Exception err)
                    {
                        this.Logger.Error("重入队列[" + QueueType.QueueReset.ToString() + "]出错", err);
                    }
                }
            });
        }

        /// <summary>
        /// 
        /// </summary>
        public void Dispose()
        {
            Stop();
        }
    }

}
